#pragma once
#include <iostream>
#include <queue>
#include <pthread.h>
#include <time.h>
#include <cstdlib>
#include <unistd.h>

namespace Mango
{
    const int default_cap = 5;
    template<class T>
    class BlockQueue
    {
        public:
            bool isFull()
            {
                return _cap == _bq.size();
            }

            bool isEmpty()
            {
                return _bq.empty();
            }

            BlockQueue(int cap = default_cap) :_cap(cap)
            {
                pthread_mutex_init(&_mtx, nullptr);//初始化锁
                //初始化条件变量
                pthread_cond_init(&_empty, nullptr);
                pthread_cond_init(&_full, nullptr);
            }

            ~BlockQueue() 
            {
                pthread_mutex_destroy(&_mtx);//释放锁
                //释放条件变量
                pthread_cond_destroy(&_empty);
                pthread_cond_destroy(&_full);
            }

            //向阻塞队列插入数据（生产者调用）
            void Push(const T& data)
            {
                pthread_mutex_lock(&_mtx);//加锁
                while (isFull())
                {
                    //此时不能进行生产,直到阻塞队列可以容纳新的数据
                    pthread_cond_wait(&_full, &_mtx);
                }
                _bq.push(data);

                if(_bq.size()>_cap/2) 
                {
                    pthread_cond_signal(&_empty); //唤醒在empty条件变量下等待的消费者线程
                }
                pthread_mutex_unlock(&_mtx);//解锁
                
            }

            //从阻塞队列获取数据（消费者调用）
            void Pop(T* data)//输出型参数
            {
                pthread_mutex_lock(&_mtx);
                while (isEmpty())
                {
                    //不能进行消费，直到阻塞队列有新的数据
                    pthread_cond_wait(&_empty, &_mtx);
                }
                *data = _bq.front();
                _bq.pop();
                    pthread_cond_signal(&_full); //唤醒在full条件变量下等待的生产者线程
                
                pthread_mutex_unlock(&_mtx);
            }
            
        private:
            std::queue<T> _bq;//阻塞队列    
            int _cap;//阻塞队列最多可以容纳的数据个数
            pthread_mutex_t _mtx;//互斥锁
            //条件变量
            //1. 当队列为满，就应该不要生产了(潜台词:不要竞争锁了)，而应该让消费者来消费
            //2. 当队列为空，就不应该消费（潜台词:不要竞争锁了）,应该让生产者来进行生产
            pthread_cond_t _full;//代表队列是满的,生产者在该条件变量下等待
	        pthread_cond_t _empty;//代表队列是空的,消费者在该条件变量下等待
    };
}